package demoMod.invincibleOne.neow;

import com.badlogic.gdx.math.Vector2;
import com.megacrit.cardcrawl.cards.AbstractCard;
import com.megacrit.cardcrawl.cards.CardGroup;
import com.megacrit.cardcrawl.cards.curses.Writhe;
import com.megacrit.cardcrawl.core.CardCrawlGame;
import com.megacrit.cardcrawl.core.Settings;
import com.megacrit.cardcrawl.dungeons.AbstractDungeon;
import com.megacrit.cardcrawl.helpers.SaveHelper;
import com.megacrit.cardcrawl.neow.NeowEvent;
import com.megacrit.cardcrawl.neow.NeowReward;
import com.megacrit.cardcrawl.random.Random;
import com.megacrit.cardcrawl.saveAndContinue.SaveFile;
import com.megacrit.cardcrawl.vfx.cardManip.PurgeCardEffect;
import com.megacrit.cardcrawl.vfx.cardManip.ShowCardAndObtainEffect;
import com.megacrit.cardcrawl.vfx.combat.HealEffect;
import demoMod.invincibleOne.InvincibleOneMod;
import demoMod.invincibleOne.actions.SelectCardInCardGroupAction;
import demoMod.invincibleOne.cards.invincible.Anarchy;
import demoMod.invincibleOne.cards.invincible.OutOfThinAir;
import demoMod.invincibleOne.enums.AbstractCardEnum;
import demoMod.invincibleOne.relics.CostOfBlessing2Artifact;
import demoMod.invincibleOne.relics.CostOfBlessing2Strength;
import demoMod.invincibleOne.ui.BingoPanel;
import demoMod.invincibleOne.ui.BingoSlot;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

public enum InvincibleRewardItem {
    GAIN_100_GOLD(false, false) {
        @Override
        public void activate() {
            CardCrawlGame.sound.play("GOLD_JINGLE");
            AbstractDungeon.player.gainGold(100);
        }
    },
    REMOVE_A_CARD(false, false) {
        @Override
        public void activate() {
            CardGroup tmp = CardGroup.getGroupWithoutBottledCards(AbstractDungeon.player.masterDeck.getPurgeableCards());
            InvincibleOneMod.addToBot(new SelectCardInCardGroupAction(1, c -> true, c -> {
                AbstractDungeon.topLevelEffects.add(new PurgeCardEffect(c, (float) Settings.WIDTH / 2.0F, (float)Settings.HEIGHT / 2.0F));
                AbstractDungeon.player.masterDeck.removeCard(c);
            }, tmp, SelectCardInCardGroupAction.TEXT[4]));
        }
    },
    TRANSFORM_A_CARD(false, false) {
        boolean activated = false;

        @Override
        public void activate() {
            activated = true;
            AbstractDungeon.gridSelectScreen.open(AbstractDungeon.player.masterDeck.getPurgeableCards(), 1, NeowReward.TEXT[25], false, true, false, false);
        }

        @Override
        public void update() {
            if (activated && !AbstractDungeon.gridSelectScreen.selectedCards.isEmpty()) {
                AbstractDungeon.transformCard(AbstractDungeon.gridSelectScreen.selectedCards.get(0), false, NeowEvent.rng);
                AbstractDungeon.player.masterDeck.removeCard(AbstractDungeon.gridSelectScreen.selectedCards.get(0));
                AbstractDungeon.topLevelEffects.add(new ShowCardAndObtainEffect(AbstractDungeon.getTransformedCard(), (float)Settings.WIDTH / 2.0F, (float)Settings.HEIGHT / 2.0F));

                AbstractDungeon.gridSelectScreen.selectedCards.clear();
                AbstractDungeon.overlayMenu.cancelButton.hide();
                SaveHelper.saveIfAppropriate(SaveFile.SaveType.POST_NEOW);
                this.activated = false;
            }
        }

        @Override
        public void reset() {
            activated = false;
        }
    },
    CHOOSE_A_CARD(false, false) {
        @Override
        public void activate() {
            AbstractDungeon.cardRewardScreen.open(getRewardCards(null), null, CardCrawlGame.languagePack.getUIString("CardRewardScreen").TEXT[1]);
        }
    },
    OBTAIN_A_RANDOM_RARE_CARD(false, false) {
        @Override
        public void activate() {
            AbstractDungeon.topLevelEffects.add(new ShowCardAndObtainEffect(AbstractDungeon.getCard(AbstractCard.CardRarity.RARE, NeowEvent.rng).makeCopy(), (float)Settings.WIDTH / 2.0F, (float)Settings.HEIGHT / 2.0F));
        }
    },
    COMPLETE_A_BINGO(false, false) {
        @Override
        public void activate() {
            InvincibleOneMod.bingoPanel.hide = false;
            BingoSlot.canInteract = true;
        }

        @Override
        public void reset() {
            BingoSlot.canInteract = false;
        }
    },
    GAIN_20_MAX_HP(true, false) {
        @Override
        public void activate() {
            AbstractDungeon.player.increaseMaxHp(20, true);
            AbstractDungeon.player.currentHealth += 20;
            AbstractDungeon.topPanel.panelHealEffect();
            AbstractDungeon.effectsQueue.add(new HealEffect(AbstractDungeon.player.hb.cX - AbstractDungeon.player.animX, AbstractDungeon.player.hb.cY, 20));
        }
    },
    GAIN_2_STRENGTH(true, false) {
        @Override
        public void activate() {
            AbstractDungeon.getCurrRoom().spawnRelicAndObtain(Settings.WIDTH / 2.0F, Settings.HEIGHT / 2.0F, new CostOfBlessing2Strength());
        }
    },
    NO_GOLD(true, false) {
        @Override
        public void activate() {
            AbstractDungeon.player.loseGold(AbstractDungeon.player.gold);
        }
    },
    GAIN_2_ARTIFACT(true, false) {
        @Override
        public void activate() {
            AbstractDungeon.getCurrRoom().spawnRelicAndObtain(Settings.WIDTH / 2.0F, Settings.HEIGHT / 2.0F, new CostOfBlessing2Artifact());
        }
    },
    OBTAIN_A_ANARCHY(true, false) {
        @Override
        public void activate() {
            AbstractCard card = new OutOfThinAir();
            card.upgrade();
            AbstractDungeon.topLevelEffects.add(new ShowCardAndObtainEffect(card, (float)Settings.WIDTH / 2.0F, (float)Settings.HEIGHT / 2.0F));
        }
    },
    GAIN_250_GOLD(false, true) {
        @Override
        public void activate() {
            CardCrawlGame.sound.play("GOLD_JINGLE");
            AbstractDungeon.player.gainGold(250);
        }
    },
    OBTAIN_A_WRITHE(false, true) {
        @Override
        public void activate() {
            AbstractDungeon.topLevelEffects.add(new ShowCardAndObtainEffect(new Writhe(), (float)Settings.WIDTH / 2.0F, (float)Settings.HEIGHT / 2.0F));
        }
    },
    CHOOSE_A_RARE_CARD(false, true) {
        @Override
        public void activate() {
            AbstractDungeon.cardRewardScreen.open(getRewardCards(AbstractCard.CardRarity.RARE), null, CardCrawlGame.languagePack.getUIString("CardRewardScreen").TEXT[1]);
        }
    },
    REMOVE_2_CARDS(false, true) {
        @Override
        public void activate() {
            CardGroup tmp = CardGroup.getGroupWithoutBottledCards(AbstractDungeon.player.masterDeck.getPurgeableCards());
            InvincibleOneMod.addToBot(new SelectCardInCardGroupAction(2, c -> true, c -> {
                AbstractDungeon.topLevelEffects.add(new PurgeCardEffect(c, (float) Settings.WIDTH / 2.0F, (float)Settings.HEIGHT / 2.0F));
                AbstractDungeon.player.masterDeck.removeCard(c);
            }, tmp, SelectCardInCardGroupAction.TEXT[4]));
        }
    },
    OBTAIN_A_RANDOM_LEGENDARY_CARD(false, true) {
        @Override
        public void activate() {
            AbstractDungeon.topLevelEffects.add(new ShowCardAndObtainEffect(AbstractDungeon.getCard(AbstractCardEnum.LEGENDARY, NeowEvent.rng).makeCopy(), (float)Settings.WIDTH / 2.0F, (float)Settings.HEIGHT / 2.0F));
        }
    },
    UPGRADE_2_CARDS(true, false) {
        @Override
        public void activate() {
            List<AbstractCard> basicCardList = AbstractDungeon.player.masterDeck.group.stream().filter(c -> c.rarity == AbstractCard.CardRarity.BASIC).collect(Collectors.toList());
            Collections.shuffle(basicCardList, new java.util.Random(AbstractDungeon.miscRng.randomLong()));
            int amount = 0;
            for (AbstractCard card : basicCardList) {
                if (amount < 2 && card.canUpgrade()) {
                    card.upgrade();
                    amount++;
                }
            }
        }
    }
    ;
    private final boolean isNegative;

    private final boolean isStrongPositive;

    private final String description;

    InvincibleRewardItem(boolean isNegative, boolean isStrongPositive) {
        this.isNegative = isNegative;
        this.isStrongPositive = isStrongPositive;
        this.description = CardCrawlGame.languagePack.getUIString(InvincibleOneMod.makeID(name())).TEXT[0];
    }

    public void activate() {}

    public void update() {}

    public void reset() {}

    public boolean isNegative() {
        return isNegative;
    }

    public boolean isStrongPositive() {
        return isStrongPositive;
    }

    public String getDescription() {
        return description;
    }

    public static ArrayList<AbstractCard> getRewardCards(AbstractCard.CardRarity r) {
        ArrayList<AbstractCard> retVal = new ArrayList<>();
        int numCards = 3;

        for(int i = 0; i < numCards; ++i) {
            r = r == null ? rollRarity() : r;

            AbstractCard card = null;
            switch (r) {
                case RARE:
                case COMMON:
                case UNCOMMON:
                    card = getCard(r);
                    break;
                default:
            }

            while(retVal.contains(card)) {
                card = getCard(r);
            }

            retVal.add(card);
        }

        ArrayList<AbstractCard> retVal2 = new ArrayList<>();

        for (AbstractCard c : retVal) {
            retVal2.add(c.makeCopy());
        }

        return retVal2;
    }

    public static AbstractCard.CardRarity rollRarity() {
        if (NeowEvent.rng == null) {
            NeowEvent.rng = new Random(Settings.seed);
        }
        return NeowEvent.rng.randomBoolean(0.33F) ? AbstractCard.CardRarity.UNCOMMON : AbstractCard.CardRarity.COMMON;
    }

    public static AbstractCard getCard(AbstractCard.CardRarity rarity) {
        if (NeowEvent.rng == null) {
            NeowEvent.rng = new Random(Settings.seed);
        }
        switch (rarity) {
            case RARE:
                return AbstractDungeon.rareCardPool.getRandomCard(NeowEvent.rng);
            case UNCOMMON:
                return AbstractDungeon.uncommonCardPool.getRandomCard(NeowEvent.rng);
            case COMMON:
                return AbstractDungeon.commonCardPool.getRandomCard(NeowEvent.rng);
            default:
                return null;
        }
    }
}
